package com.gqzm.side.common.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.gqzm.side.domain.bo.*;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import oshi.SystemInfo;
import oshi.hardware.*;
import oshi.software.os.FileSystem;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * @ClassName: {@link OshiUtils}
 * @description: 系统运行参数获取工具类
 * @author: peter qin
 * @date: 2023 12 14
 * @version: 1.0
 **/
@UtilityClass
public class OshiUtils {
    private static final int OSHI_WAIT_SECOND = 1000;
    private static final SystemInfo systemInfo = new SystemInfo();
    private static final HardwareAbstractionLayer hardware = systemInfo.getHardware();
    private static final OperatingSystem operatingSystem = systemInfo.getOperatingSystem();

    @Setter
    private static NetworkInfo NETWORK_INFO;

    public static NetworkInfo getNETWORK_INFO() {
        if (NETWORK_INFO == null) {
            setNETWORK_INFO(netInfo());
        }
        return NETWORK_INFO;
    }


    private static final String PERCENTAGE_FORMAT = "#.##%";

    public static BoxCpuInfo cpuInfo() {
        CentralProcessor processor = hardware.getProcessor();
        // CPU信息
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()]
                - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()]
                - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()]
                - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()]
                - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()]
                - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()]
                - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()]
                - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()]
                - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
//        //cpu核数
//        cpuInfo.put("cpu_num", processor.getLogicalProcessorCount());
//        //cpu系统使用率
//        cpuInfo.put("c_sys", new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));
//        //cpu用户使用率
//        cpuInfo.put("user", new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));
//        //cpu当前等待率
//        cpuInfo.put("iowait", new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));
//        //cpu当前使用率
//        cpuInfo.put("idle", new DecimalFormat("#.##%").format(1.0 - (idle * 1.0 / totalCpu)));
        return BoxCpuInfo.builder()
                .temperature(temperatureRandom())
                .cpuNum(processor.getLogicalProcessorCount())
                .cpuSys(new DecimalFormat(PERCENTAGE_FORMAT)
                        .format(cSys * 1.0 / totalCpu))
                .cpuUser(new DecimalFormat(PERCENTAGE_FORMAT)
                        .format(user * 1.0 / totalCpu))
                .ioWait(new DecimalFormat(PERCENTAGE_FORMAT)
                        .format(iowait * 1.0 / totalCpu))
                .idle(new DecimalFormat(PERCENTAGE_FORMAT)
                        .format(1.0 - (idle * 1.0 / totalCpu)))
                .build();
    }

    private static final Random random = new Random();

    private static Double temperatureRandom() {
        return (random.nextInt(10000) / 10000.0D) * (50 - 20) + 20;
    }


    private static Double randomGpuUsed() {
        return (random.nextInt(10000) / 10000.d) * 6;
    }

    public static synchronized NetworkInfo netInfo() {
        List<NetworkIF> nets = hardware.getNetworkIFs()
                .stream()
                .filter(o -> o.getBytesRecv() > 0
                        || o.getBytesSent() > 0)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(nets)) {
            return null;
        }
        NetworkInfo r = null;
        for (NetworkIF o : nets) {
            r = NetworkInfo.builder()
                    .name(o.getDisplayName())
                    .build();
            calculateSpeed(r, o);
            if (r.getRecvKbps() > 0 || r.getSendKbps() > 0) {
                return r;
            }
        }
        return r;
    }


    private static void calculateSpeed(NetworkInfo result,
                                       NetworkIF o) {
        long recv1 = o.getBytesRecv();
        long send1 = o.getBytesSent();
        long t1 = System.currentTimeMillis();
        Util.sleep(3000);
        o.updateAttributes();
        long recv2 = o.getBytesRecv();
        long send2 = o.getBytesSent();
        long t2 = System.currentTimeMillis();
        long tp = t2 - t1;
        BigDecimal downloadDiff = new BigDecimal(recv2 - recv1);
        BigDecimal uploadDiff = new BigDecimal(send2 - send1);
        BigDecimal timestampDiff = new BigDecimal(tp);
        BigDecimal downloadPerSecond = downloadDiff.multiply(
                BigDecimal.valueOf(1000)).divide(timestampDiff,
                2, RoundingMode.HALF_UP);
        BigDecimal uploadPerSecond = uploadDiff.multiply(
                BigDecimal.valueOf(1000)).divide(timestampDiff,
                2, RoundingMode.HALF_UP);
        BigDecimal downKb = downloadPerSecond.divide(BigDecimal.valueOf(1024),
                0, RoundingMode.HALF_UP);
        BigDecimal uploadKb = uploadPerSecond.divide(BigDecimal.valueOf(1024),
                0, RoundingMode.HALF_UP);
        result.setRecvKbps(downKb.doubleValue());
        result.setSendKbps(uploadKb.doubleValue());
    }


    public static BoxMemInfo memInfo() {
        GlobalMemory memory = systemInfo.getHardware().getMemory();
        //总内存
        long totalByte = memory.getTotal();
        //剩余
        long acaliableByte = memory.getAvailable();
//        //总内存
//        cpuInfo.put("total", formatByte(totalByte));
//        //使用
//        cpuInfo.put("used", formatByte(totalByte - acaliableByte));
//        //剩余内存
//        cpuInfo.put("free", formatByte(acaliableByte));
//        //使用率
//        cpuInfo.put("usage_rate", new DecimalFormat("#.##%").format((totalByte - acaliableByte) * 1.0 / totalByte));
        return BoxMemInfo.builder()
                .total(formatByte(totalByte))
                .used(formatByte(totalByte - acaliableByte))
                .free(formatByte(acaliableByte))
                .usage(new DecimalFormat("#.##%")
                        .format((totalByte - acaliableByte) * 1.0 / totalByte))
                .build();
    }


    public static List<GpuInfo> gpuInfo() {
        List<GraphicsCard> gc = hardware.getGraphicsCards();
        return gc.stream()
                .map(o -> GpuInfo.builder()
                        .name(o.getName())
                        .totalMem(8.0)
                        .usedMem(randomGpuUsed())
                        .temperature(temperatureRandom())
                        .build())
                .collect(Collectors.toList());
    }


    private static double gbFormat(long bts) {
        double FORMAT = 1024.0;
        return bts / FORMAT / FORMAT / FORMAT;
    }

    private static String formatByte(long byteNumber) {
        //换算单位
        double FORMAT = 1024.0;
        double kbNumber = byteNumber / FORMAT;
        if (kbNumber < FORMAT) {
            return new DecimalFormat("#.##KB").format(kbNumber);
        }
        double mbNumber = kbNumber / FORMAT;
        if (mbNumber < FORMAT) {
            return new DecimalFormat("#.##MB").format(mbNumber);
        }
        double gbNumber = mbNumber / FORMAT;
        if (gbNumber < FORMAT) {
            return new DecimalFormat("#.##GB").format(gbNumber);
        }
        double tbNumber = gbNumber / FORMAT;
        return new DecimalFormat("#.##TB").format(tbNumber);
    }

    public static void sysInfo() throws UnknownHostException {
//        JSONObject cpuInfo = new JSONObject();
        Properties props = System.getProperties();
        SystemStaticInfo.setOsName(props.getProperty("os.name"));
        SystemStaticInfo.setOsArch(props.getProperty("os.arch"));
        SystemStaticInfo.setComputerName(InetAddress.getLocalHost().getHostName());
        SystemStaticInfo.setComputerIp(InetAddress.getLocalHost().getHostAddress());
        //操作系统名
//        cpuInfo.put("os_name", props.getProperty("os.name"));
        //系统架构
//        cpuInfo.put("os_arch", props.getProperty("os.arch"));
        //服务器名称
//        cpuInfo.put("computer_name", InetAddress.getLocalHost().getHostName());
        //服务器Ip
//        cpuInfo.put("computer_ip", InetAddress.getLocalHost().getHostAddress());
        //项目路径
//        cpuInfo.put("user_dir", props.getProperty("user.dir"));
    }

    public static List<BoxMonitorDisk> sysFileInfo() {
        FileSystem fileSystem = operatingSystem.getFileSystem();
        SystemStaticInfo.setDisks(fileSystem.getFileStores()
                .stream()
                .map(o -> BoxMonitorDisk.builder()
                        .diskName(o.getMount())
                        .sysTypeName(o.getType())
                        .free(gbFormat(o.getUsableSpace()))
                        .temperature(temperatureRandom())
                        .typeName(o.getName())
                        .total(gbFormat(o.getTotalSpace()))
                        .used(gbFormat(o.getTotalSpace() - o.getUsableSpace()))
                        .build())
                .collect(Collectors.toList()));
        return SystemStaticInfo.getDisks();
//        for (OSFileStore fs : fsArray) {
//            cpuInfo = new JSONObject();
//            //盘符路径
//            cpuInfo.put("dir_name", fs.getMount());
//            //盘符类型
//            cpuInfo.put("sys_type_name", fs.getType());
//            //文件类型
//            cpuInfo.put("type_name", fs.getName());
//            //总大小
//            cpuInfo.put("total", formatByte(fs.getTotalSpace()));
//            //剩余大小
//            cpuInfo.put("free", formatByte(fs.getUsableSpace()));
//            //已经使用量
//            cpuInfo.put("used", formatByte(fs.getTotalSpace() - fs.getUsableSpace()));
//            if (fs.getTotalSpace() == 0) {
//                //资源的使用率
//                cpuInfo.put("usage", 0);
//            } else {
//                cpuInfo.put("usage",new DecimalFormat("#.##%").format((fs.getTotalSpace() - fs.getUsableSpace()) * 1.0 / fs.getTotalSpace()));
//            }
//            sysFiles.add(cpuInfo);
//        }
    }


}
